export default function debounce(fn, delay, immediate = false) {
  const _debounce = function (...args) {
    let timer = null
    let isInvoke = false

    return new Promise((resolve, reject) => {
      try {
        if (timer) clearTimeout(timer)

        let res = undefined
        if (immediate && !isInvoke) {
          res = fn.apply(this.args)
          resolve(res)
          isInvoke = true
          return
        }

        timer = setTimeout(() => {
          res = fn.apply(this, args)
          resolve(res)
          timer = null
          isInvoke = fasle
        }, delay)
      } catch (error) {
        reject(new Error(error))
      }
    })
  }

  _debounce.cancel = function () {
    if (timer) clearTimeout(timer)
    timer = null
    isInvoke = false
  }

  return _debounce
} 